package org.tagging.service.impl.malay;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.tagging.dao.malay.MalayMapper;
import org.tagging.model.TaggingIndonesian;
import org.tagging.model.TaggingMalay;
import org.tagging.model.UnknownWordMalay;
import org.tagging.service.TaggingService;
import org.tagging.service.impl.other.ClientUserServiceImpl;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 此处可考虑合并所有语言的mapper构造出一个通用的CommonMapper，其中表名为可传入的参数
 */
@Service
public class MalayServiceImpl implements TaggingService<TaggingMalay> {
    @Resource
    private MalayMapper malayMapper;
    @Autowired
    private ClientUserServiceImpl userService;
    @Autowired
    private AbbreviationMalayServiceImpl abbreviationService;
    @Autowired
    private UnknownWordMalayServiceImpl unknownWordService;


    private void updateUsingBy(List<TaggingMalay> taggingMalays) {
        TaggingMalay malay = new TaggingMalay();
        Integer userId = userService.retrieveCurrentUserId();
        for (TaggingMalay taggingMalay : taggingMalays) {
            malay.setId(taggingMalay.getId());
            malay.setUsingBy(userId);
            updateSelective(malay);
        }
    }

    @Override
    public void clearUsingBy(Integer tagId) {
        TaggingMalay malay = new TaggingMalay();
        malay.setId(tagId);
        malay.setUsingBy(-1);
        malayMapper.updateSelective(malay);
    }

    @Override
    public void translate(Integer id, String translation) {
        System.out.println("UNSUPPORTED MALAY LANGUAGE!");
        throw new UnsupportedOperationException("translate malay unsupport!");
    }

//    @Override
//    public void updateUpdateBy(Integer id) {
//        TaggingMalay malay = new TaggingMalay();
//        malay.setId(id);
//        updateSelective(malay);
//        userService.incrementComplete("indonesian");
//    }

    //    @Override
    @Override
    public List<TaggingMalay> list(Integer size) {
        List<TaggingMalay> ts = malayMapper.listNotUsingAndUpdated(size);
        updateUsingBy(ts);
        return ts;
    }

    @Override
    public List<TaggingMalay> listNotTranslate(Integer size) {
        List<TaggingMalay> taggingMalays = malayMapper.listNotUsingAndTranslated(size);
        updateUsingBy(taggingMalays);
        return taggingMalays;
    }

    @Override
    public List<TaggingMalay> listNotAbbreviate(Integer size) {
        List<TaggingMalay> taggingMalays = malayMapper.listNotUsingAndAbbreviated(size);
        updateUsingBy(taggingMalays);
        return taggingMalays;
    }

    @Override
    public List<TaggingMalay> listNotUnknownWord(Integer size) {
        List<TaggingMalay> taggingMalays = malayMapper.listNotUsingAndUnknownWorded(size);
        updateUsingBy(taggingMalays);
        return taggingMalays;
    }

    @Override
    public void updateSelective(TaggingMalay malay) {
        malay.setUpdateTime(LocalDateTime.now());
        malayMapper.updateSelective(malay);
    }

    @Override
    public void updateUpdateByAndTranslated(Integer id) {
        Integer userId = userService.retrieveCurrentUserId();
        TaggingMalay malay = new TaggingMalay();
        malay.setId(id);
        malay.setUpdateBy(userId);
        malay.setUpdateByTranslation(userId);
        updateSelective(malay);
    }

    @Override
    public void updateUpdateByAndAbbreviation(Integer tagId) {
        Integer userId = userService.retrieveCurrentUserId();
        TaggingMalay malay = new TaggingMalay();
        malay.setUpdateBy(userId);
        malay.setId(tagId);
        malay.setUpdateByAbbreviation(userId);
        updateSelective(malay);
    }

    @Override
    public void updateUpdateByAndUnknownWord(Integer tagId) {
        Integer userId = userService.retrieveCurrentUserId();
        TaggingMalay malay = new TaggingMalay();
        malay.setUpdateBy(userId);
        malay.setId(tagId);
        malay.setUpdateByUnknownWord(userId);
        updateSelective(malay);
    }


    private static List<String> abbreviationList;
    private static List<String> abbreviationCompleteList;
    private static List<String> abbreviationCompleteChineseList;
    private static List<String> abbreviationCompleteManualList;
    private static List<String> unknownWordList;
    private static List<String> unknownWordCategoryList;
    private static List<String> unknownWordRemarkList;
    private static List<String> unknownWordCorrectList;
    private static Set<String> skipFields;

    static {
        abbreviationList = new LinkedList<>();
        abbreviationCompleteList = new LinkedList<>();
        abbreviationCompleteChineseList = new LinkedList<>();
        abbreviationCompleteManualList = new LinkedList<>();
        unknownWordList = new LinkedList<>();
        unknownWordCategoryList = new LinkedList<>();
        unknownWordRemarkList = new LinkedList<>();
        unknownWordCorrectList = new LinkedList<>();
        skipFields = new HashSet<>();
        skipFields.add("usingBy");
        skipFields.add("updateBy");
        skipFields.add("updateByTranslation");
        skipFields.add("updateByUnknownWord");
        skipFields.add("updateByAbbreviation");
    }

    @Override
    public List<TaggingMalay> queryByTimePeriod(LocalDateTime startTime, LocalDateTime endTime, int mode) {
        return malayMapper.queryByTimePeriod(startTime, endTime, mode);
    }

    @Override
    public Workbook constructWorkbookByTimePeriod(LocalDateTime startTime, LocalDateTime endTime, int mode) {
        List<TaggingMalay> taggings = queryByTimePeriod(startTime, endTime, mode);
//        List<AbbreviationMalay> abbreviationIndonesians = abbreviationService.queryByTimePeriod(startTime, endTime, mode);
        List<UnknownWordMalay> unknownWordss = unknownWordService.queryByTimePeriod(startTime, endTime, mode);

        Workbook workbook = new HSSFWorkbook();
        Sheet sheet = workbook.createSheet();
        Row row = sheet.createRow(0);
        Map<String, Integer> map = preConstruct(TaggingIndonesian.class, skipFields);
        preConstruct(row, map);
        int i = 1;
        for (TaggingMalay t : taggings) {
            Row r = sheet.createRow(i++);
            map.forEach((fieldName, index) -> {
                try {
                    Object valueInvoke = valueInvoke(t, fieldName);
                    r.createCell(index).setCellValue(valueInvoke!=null?String.valueOf(valueInvoke):"");
                } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                    e.printStackTrace();
                }
            });
            //处理unknownWords
//            List<UnknownWordMalay> unknownWords = unknownWordService.queryByTagId(t.getId());
            List<UnknownWordMalay> ukws = searchUnknownWordsByTagId(unknownWordss, t.getId());
            ukws.forEach(each -> {
                unknownWordList.add(each.getUnknownWord() == null ? "" : each.getUnknownWord());
                unknownWordCategoryList.add(each.getCategory() == null ? "" : each.getCategory());
                unknownWordRemarkList.add(each.getRemark() == null ? "" : each.getRemark());
                unknownWordCorrectList.add(each.getUnknownWordCorrect() == null ? "" : each.getUnknownWordCorrect());
            });
            String unknownWords = Arrays.toString(unknownWordList.toArray());
            r.createCell(map.size() + 1).setCellValue(unknownWords);
            String unknownWordCategories = Arrays.toString(unknownWordCategoryList.toArray());
            r.createCell(map.size() + 2).setCellValue(unknownWordCategories);
            String unknownWordRemarks = Arrays.toString(unknownWordRemarkList.toArray());
            r.createCell(map.size() + 3).setCellValue(unknownWordRemarks);
            String unknownWordCorrects = Arrays.toString(unknownWordCorrectList.toArray());
            r.createCell(map.size() + 4).setCellValue(unknownWordCorrects);
            unknownWordList.clear();
            unknownWordCategoryList.clear();
            unknownWordCorrectList.clear();
            unknownWordRemarkList.clear();
        }
        return workbook;
    }

    private List<UnknownWordMalay> searchUnknownWordsByTagId(List<UnknownWordMalay> unknownWordss, Integer tagId) {
        if (unknownWordss.size() == 0) {
            return new ArrayList<>(0);
        }
        int left = 0;
        int right = unknownWordss.size() - 1;
        int target = -1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (tagId.equals(unknownWordss.get(mid).getTagId())) {
                target = mid;
                break;
//                return mid;
            } else if (tagId.compareTo(unknownWordss.get(mid).getTagId()) > 0) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        if (target == -1) {
            return new ArrayList<>(0);
        }
        //若能找到这个坐标，向其左右延申并记录下来其坐标
        List<UnknownWordMalay> targets = new LinkedList<>();
        targets.add(unknownWordss.get(target));
        int t1 = target;
        while ((t1 = t1 - 1) > 0 && unknownWordss.get(t1).getTagId().equals(unknownWordss.get(target).getTagId())) {
            targets.add(unknownWordss.get(t1));
        }
        int t2 = target;
        while ((t2 = t2 + 1) < unknownWordss.size() && unknownWordss.get(t2).getTagId().equals(unknownWordss.get(target).getTagId())) {
            targets.add(unknownWordss.get(t2));
        }
        return targets;
    }

    private Object valueInvoke(TaggingMalay t, String fieldName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method method = t.getClass().getMethod("get" + toCapital(fieldName));
        return method.invoke(t);
    }

    private void preConstruct(Row r, Map<String, Integer> map) {
        map.forEach((field, index) -> {
            r.createCell(index).setCellValue(field);
        });
//        r.createCell(map.size()).setCellValue("abbreviation");
//        r.createCell(map.size() + 1).setCellValue("abbreviationComplete");
//        r.createCell(map.size() + 2).setCellValue("abbreviationCompleteChinese");
//        r.createCell(map.size() + 3).setCellValue("abbreviationCompleteManual");
        r.createCell(map.size() + 1).setCellValue("unknownWords");
        r.createCell(map.size() + 2).setCellValue("unknownWordCategories");
        r.createCell(map.size() + 3).setCellValue("unknownWordRemarks");
        r.createCell(map.size() + 4).setCellValue("unknownWordCorrects");
    }


}
